﻿using System;
using System.Linq;
using KPIS.GERP.Models;
using System.Data.Entity;
using KPIS.GERP.Models.HRM;
using KPIS.GERP.Models.SYS;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace KPIS.GERP.WCF.SYS
{
    public partial class SysApprovalService
    {
        public ICollection<ApprovePathSimulate> LoadApprovePathSimulate(int applyToEmpId, int appPrcId)
        {
            return LoadApprovePathSimulate(applyToEmpId, appPrcId);
        }

        public ICollection<ApprovePathSimulate> LoadApprovePathSimulate2(int applyToEmpId, int? relatedEmpId, int? createdByEmpId, int appPrcId)
        {
            var db = new GERPContext(false); 
            return LoadApprovePathSimulate(ref db, applyToEmpId, appPrcId, true, relatedEmpId, createdByEmpId);
        } 

        public ICollection<ApprovePathSimulate> LoadApprovePathSimulate(ref GERPContext db, int applyToEmpId, int appPrcId, bool loadViaNetwork = false,
                                                                        int? relatedToEmpId = null, int? createdByEmpId = null)
        {
            List<ApprovePathSimulate> result = new List<ApprovePathSimulate>();
            int simulateStepNo = 1;

            var requesterEmployee = db.Employees
                .Include(o => o.Position.WorkingUpperPosition)
                .FirstOrDefault(o => o.EmpId == applyToEmpId && o.RecordStatus != "D");

            var positions = db.Positions
                .Include(o => o.WorkingUpperPosition)
                .Where(o => o.RecordStatus != "D")
                .ToList();

            var appPaths = db.ApprovePaths
                .Include(o => o.ApproveProcess.ApproveProcessGroup)
                .Where(o => o.AppPrcId == appPrcId && o.RecordStatus == "U")
                .OrderBy(o => o.StepNo)
                .ToList();

            if (requesterEmployee == null) throw new Exception("ไม่พบข้อมูลผู้ทำคำขอ");
            if (requesterEmployee == null || requesterEmployee.Position == null) throw new Exception("ไม่พบข้อมูลตำแหน่งผู้ทำคำขอ");
            if (appPaths == null || !appPaths.Any()) throw new Exception("ไม่พบขั้นตอนในสายบังคับบัญชาสำหรับ ประเภทการอนุมัติ : " + appPrcId);

            Position p = requesterEmployee.Position.WorkingUpperPosition;

            // apppath step 1, 2, 3
            foreach (var appPath in appPaths)
            {
                // approver type 
                /*
                    JobSiteHead = 0, หัวหน้าสำนัก ส่งขึ้นทีละระดับ จนถึง หัวหน้าสำนัก (ExecPosSeq = 251)
                    Position = 1, ส่งตรงถึงตำแหน่งใดๆ
                    PositionGroup = 2, // ส่งตรงถึง กลุ่มตำแหน่งใดๆ (ยังไม่ได้ Develop) ต้องมีการสร้างเทเบิ้ลกลุ่มตำแหน่ง
                    ExecPositionGroup = 3,  // ส่งถึงคนที่เป็นตำแหน่งบริหารใดๆ ตอนนี้ไม่ได้ใช้
                    WaitRequesterSendBack = 4, // ตอนสร้างคำขอจะไม่มี เป็นตัวเลือกที่ใช้ระหว่างพิจารณา
                    FieldApplyTo = 5, // ส่งถึง ผู้ที่ได้รับผลจากการทำคำขอ เช่น ขอลา ผู้ใดรับผลคือผู้ลา          ขออนุมัติรักษาการ ผู้ได้รับผลคือ ผู้รักษาการณ์
                    FieldRelatedTo = 6  // ส่งถึง ผู้ที่เกี่ยวข้องการทำคำขอ เช่น          ขออนุมัติรักษาการ ผู้เกี่ยวข้องคือ ผู้ที่จะไม่อยู่ทำงาน และมีคนอื่นมารักษาการณ์แทน
                */
                switch (appPath.ApproverType)
                {
                        // Fix position 
                    case ApproverType.Position:
                        p = positions.FirstOrDefault(o => o.PosId == appPath.PosId);
                        result.Add(new ApprovePathSimulate
                            {
                                SimulateStepNo = simulateStepNo++,
                                AppPathStepNo = appPath.StepNo,
                                ApproverPosId = appPath.PosId,
                                ApproverPosition = p,
                                ApprovePathState = ApprovePathState.After,
                                AppPathId = appPath.AppPathId,
                                ApproverType = appPath.ApproverType,
                                ApprovePath = appPath,
                                IsForNotice = appPath.IsForNotice
                            });
                        break;
                    case ApproverType.ExecPositionGroup:
                        int roundStepNo1 = 1;
                        p = requesterEmployee.Position;// start from him self
                        //requesterEmployee.Position.WorkingUpperPosition

                        bool found = false;
                        do
                        {
                            if (p.ExecPosId == appPath.ExecPosId)
                            {
                                var newSim = new ApprovePathSimulate
                                {
                                    SimulateStepNo = simulateStepNo++,
                                    AppPathStepNo = appPath.StepNo,
                                    ApproverPosId = p.PosId,
                                    ApproverPosition = p,
                                    AppPathSubStepNo = null,
                                    ApprovePathState = ApprovePathState.After,
                                    AppPathId = appPath.AppPathId,
                                    ApproverType = appPath.ApproverType,
                                    ApprovePath = appPath,
                                    IsForNotice = appPath.IsForNotice
                                };
                                result.Add(newSim);
                                found = true;
                                break;
                            }
                        } while ((p = p.WorkingUpperPosition) != null);
                        
                        if(!found && (p = requesterEmployee.Position.WorkingUpperPosition) != null)
                        {  
                            var newSim = new ApprovePathSimulate
                            {
                                SimulateStepNo = simulateStepNo++,
                                AppPathStepNo = appPath.StepNo,
                                ApproverPosId = p.PosId,
                                ApproverPosition = p,
                                AppPathSubStepNo = null,
                                ApprovePathState = ApprovePathState.After,
                                AppPathId = appPath.AppPathId,
                                ApproverType = appPath.ApproverType,
                                ApprovePath = appPath,
                                IsForNotice = appPath.IsForNotice
                            };
                            result.Add(newSim); 
                        }else if(!found)
                        {
                            p = positions.First(o => o.PosId == 32);
                            if(p  != null)
                            {
                                var newSim = new ApprovePathSimulate
                                {
                                    SimulateStepNo = simulateStepNo++,
                                    AppPathStepNo = appPath.StepNo,
                                    ApproverPosId = p .PosId,
                                    ApproverPosition = p ,
                                    AppPathSubStepNo = null,
                                    ApprovePathState = ApprovePathState.After,
                                    AppPathId = appPath.AppPathId,
                                    ApproverType = appPath.ApproverType,
                                    ApprovePath = appPath,
                                    IsForNotice = appPath.IsForNotice
                                };
                                result.Add(newSim);
                            }
                        }
                        break;
                    case ApproverType.JobSiteHead:
                        int roundStepNo = 1;
                        do
                        {
                            if (p == null)
                            {
                                // if first step not found uppwer, use ผอ.
                                p = positions.First(o => o.PosId == 32);
                            }

                            if (roundStepNo == 1 && requesterEmployee.Position.ExecPosId == 251)
                            {
                                p = requesterEmployee.Position;
                            }


                            bool isExecutable = p.WorkingUpperPosition == null || p.ExecPosId == 251;
                            bool isForwardable = appPath != appPaths.Last() || (p.WorkingUpperPosition != null || p.ExecPosId != 251);
                            var newSim = new ApprovePathSimulate
                                {
                                    SimulateStepNo = simulateStepNo++,
                                    AppPathStepNo = appPath.StepNo,
                                    ApproverPosId = p.PosId,
                                    ApproverPosition = p,
                                    AppPathSubStepNo = roundStepNo++,
                                    ApprovePathState = ApprovePathState.After,
                                    AppPathId = appPath.AppPathId,
                                    ApproverType = appPath.ApproverType,
                                    ApprovePath = appPath,
                                    IsForNotice = appPath.IsForNotice
                                };
                            result.Add(newSim);

                            // ถ้าเป็นหัวหน้าให้จบ
                            if (p.ExecPosId == 251) break;

                        } while ((p = p.WorkingUpperPosition) != null);
                        break;
                    case ApproverType.FieldApplyTo:
                        var employeeApplyTo = db.Employees.FirstOrDefault(o => o.EmpId == applyToEmpId && o.RecordStatus != "D");
                        var newSim3 = new ApprovePathSimulate
                            {
                                SimulateStepNo = simulateStepNo++,
                                AppPathStepNo = appPath.StepNo,
                                ApproverPosId = employeeApplyTo.PosId,
                                ApproverPosition = employeeApplyTo.Position,
                                ApprovePathState = ApprovePathState.After,
                                AppPathId = appPath.AppPathId,
                                ApproverType = appPath.ApproverType,
                                ApprovePath = appPath,
                                IsForNotice = appPath.IsForNotice
                            };
                        result.Add(newSim3);
                        break;
                    case ApproverType.FieldRelatedTo:
                        var employeeRelatedTo = db.Employees.FirstOrDefault(o => o.EmpId == relatedToEmpId && o.RecordStatus != "D");
                        var newSim4 = new ApprovePathSimulate
                            {
                                SimulateStepNo = simulateStepNo++,
                                AppPathStepNo = appPath.StepNo,
                                ApproverPosId = employeeRelatedTo.PosId,
                                ApproverPosition = employeeRelatedTo.Position,
                                ApprovePathState = ApprovePathState.After,
                                AppPathId = appPath.AppPathId,
                                ApproverType = appPath.ApproverType,
                                ApprovePath = appPath,
                                IsForNotice = appPath.IsForNotice
                            };
                        result.Add(newSim4);
                        break;
                }
            }


            // 1. หาซ้ำ
            List<int> removeList = new List<int>();
            for (int i = 0; i < result.Count; i++)
            {
                var approvePathSimulate = result[i];
                bool foundInNextStep = false;
                for (int j = i + 1; j < result.Count; j++)
                {
                    var approvePathSimulateWalker = result[j];
                    if (approvePathSimulate.ApproverPosId == approvePathSimulateWalker.ApproverPosId)
                    { 
                        foundInNextStep = true;
                        break;
                    }
                }

                if (foundInNextStep)
                {
                    removeList.Add(i);
                }
            }

            // 2 ตัวเองเป็นผู้อนุมัติ แล้วไปผ่านคนอื่น ที่อยู่เหนือกว่า
            if (result.Count >= 2 &&
                result.Last().ApproverPosId == requesterEmployee.PosId)
            {
                if (result[0].ApproverPosId == requesterEmployee.Position.WorkingUpperPosId)
                {
                    if (!removeList.Exists(o => o == result.Count - 1))
                    {
                        removeList.Add(result.Count - 1);
                    }
                }
            }

            var resultFiltered = new List<ApprovePathSimulate>();
            for (int i = 0; i < result.Count; i++)
            {
                if (!removeList.Exists(o => o == i))
                {
                    resultFiltered.Add(result[i]);
                }
            }


            foreach (var s in resultFiltered)
            {
                // ยกเลิการใช้ระบบอ้างอิงด้วย EmpId
                //if(db.Employees.FirstOrDefault(o=>o.RecordStatus != "D" && o.PosId == s.ApproverPosId) == null)
                //{
                //    db.Employees.Add(new Employee
                //        {
                //            FirstName = "(สำหรับผู้ดำรงตำแหน่ง)",
                //            LastName = (from pName in db.Positions
                //                        where pName.RecordStatus != "D" && pName.PosId == s.ApproverPosId
                //                        select pName.Name).FirstOrDefault(),
                //            RecordStatus = "U",
                //            GenderId = 1,
                //            NamePrefixId = 3,
                //            ReligionId = 1,
                //            NationalId = 1,
                //            EmpTypeId = 1,
                //            PosId = s.ApproverPosId,
                //            WorkingJobSiteId = 1,
                //            EmpStatusId = 101,
                //            BirthDate = DateTime.Now,
                //            Citizen = "0000000000000",
                //            IsMockEmployee = true
                //        });
                //    db.SaveChanges();
                //}
                //// กรณีแจ้งเตือนอย่างเดียว
                //if (s.IsForNotice)
                //{
                //    continue;
                //}

                // override mistake config
                if (s != resultFiltered.Last())
                {
                    s.IsForwardable = true;
                }
                if (s == resultFiltered.Last())
                {
                    s.IsApproveAble = true;
                }
                s.IsRejectable = true;
                s.IsSendBackable = true;
            }

            bool foundCreatedByInApprovalLine = false;
            foreach (var s in resultFiltered)
            {
                if(s.ApproverPosId == createdByEmpId)
                {
                    foundCreatedByInApprovalLine = true;
                    break;
                }
            }

            /*
            List<ApprovePathSimulate> simulates = new List<ApprovePathSimulate>();
            int? posId = db.Employees.FirstOrDefault(o => o.EmpId == createdByEmpId).PosId;
            if(foundCreatedByInApprovalLine)
            {
                foundCreatedByInApprovalLine = false;
                foreach (var s in result)
                {
                    if(s.ApproverPosId == posId)
                    {
                        foundCreatedByInApprovalLine = true; 
                    }

                    if(foundCreatedByInApprovalLine)
                    {
                        simulates.Add(s);
                    }
                }
                result = simulates;
            }*/

            if (loadViaNetwork)
            {
                foreach (var r in resultFiltered)
                {
                    try
                    {
                        r.ApprovePath.ApproveProcess = null;
                    }
                    catch (Exception ex)
                    {
                        var ex2 = ex;
                    }
                }
            }

            int k = 1;
            foreach (var r in resultFiltered)
            {
                r.SimulateStepNo = k++;
            }


            resultFiltered = resultFiltered.OrderBy(o => o.SimulateStepNo).ToList();
            return resultFiltered;
        }
    }
}